Related links:
All qmail/mess822-related patches and scripts here are in the public domain.
The qmail-realrcptto
patch copies logic from qmail-send,
qmail-lspawn, qmail-getpw, and
qmail-local into qmail-smtpd and
qmail-qmtpd, so that if a local delivery (i.e., one for a domain
in /var/qmail/control/locals or virtualdomains)
would eventually bounce due to a missing .qmail file, then that
recipient address is rejected during the SMTP or QMTP protocol conversation.
There are other qmail patches around that do similar jobs (badrcptto, etc.);
the focus of this patch is to get this functionality with no additional
administrative effort, rather than qmail-smtpd's running speed.
You just set up your .qmail files, as you would have to do
anyway, and the rest is automatic, though slower than a CDB lookup.
Addresses which use the default delivery instructions are never rejected by
this patch, because they would never be bounced due to the lack of a
.qmail file. If you're not sure whether this patch will reject
mail for certain addresses on your system, you can check using the qtraceaddr script below. If it reports
“bounce message due to lack of a .qmail file”, then
qmail-realrcptto will reject mail for that address; otherwise mail will be
accpeted.
This makes less work for the qmail machine, since these undeliverable addresses are rejected before ever entering the qmail queue (but it makes more work - to perform the check itself - in cases that would not bounce). Joe-job double bounces are also eliminated.
Note that with this patch, qmail-smtpd and
qmail-qmtpd will always use the latest versions of the control
files envnoathost, locals,
percenthack, and virtualdomains, while
qmail-send will use its cached copy in memory until it receives
SIGHUP or is restarted. (Even after SIGHUP,
qmail-send still uses the old envnoathost and
percenthack.) So after control files are changed, and before
qmail-send is notified, it is possible that a message recipient
might be accepted through the network even though it would bounce later, or a
message recipient might be rejected through the network even though the
delivery would succeed.
If QMAILRRTDENYALL=1 is set in the environment for
qmail-smptd and qmail-qmtpd, then each individual
recipient address will be accepted, but the whole message will be rejected,
to stop attackers from probing for valid addresses. It's still possible to
probe by sending empty, single-recipient messages, and then sending the real
message with all the recipients that weren't rejected.
This patch is less effective when there are .qmail-default
files, or when qmaild does not have sufficient filesystem
permissions to stat() users' .qmail files, since in
those cases, qmail-smtpd cannot know that the delivery would
later bounce due to the lack of a .qmail file. For example, I'm
told that this patch is not useful for virtual domains managed with vpopmail,
since an applicable .qmail-default file always exists. (I'm not
familiar with vpopmail myself.) The patch may still be useful for other
local or virtual domains on the same server, if they are not managed by
vpopmail.
The qmail-branch patch
enhances the .qmail delivery instruction language, narrowing the
gap between qmail-local and procmail. If you have
a sequence of lines like:
?label command arg ...
...
:label
qmail-local will deliver the message to the command just as it
does for a |command line, and if the command exits with status
99, qmail-local will skip down to the :label line;
delivery instructions in the intervening lines are ignored. If the
command exits with status other than 99, the result is the same as
with a |command line. :label lines are
otherwise ignored, just like #comment lines.
A label is a (possibly empty) sequence of non-space, non-tab, nonzero
bytes. Text following a label on a ":" line is
ignored. If there is no command on a ?label line, it's
an unconditional jump. If a command exits 99 and the corresponding
label is not found, all following delivery instructions are skipped
(as with |command). There are no backward jumps.
This makes the .qmail language a little more useful, IMO,
but not enough to cause trouble. :) (You get if-then-else, but no
loops.) The syntax is a little ugly, but it gets the job done. The
same functionality is already available with |command
lines, but then you need multiple .qmail files, which
exposes extra addresses to outside senders, so it gets a little more
complicated.
A .qmail file using this feature might look like:
# Sort out mail from Sue. ?test [ "$SENDER" = sue@somewhere.org ] || exit 99 /home/b1ff/mail/sue/ # Skip all further processing. ?done :test # Is this a copy of a mailing list message? ?test iftocc `cat lists` || exit 99 # Bounce this copy. |cat duplicate; exit 100 :test # Deliver to the default mailbox. /home/b1ff/mail/main/
Another way of tackling this problem is to do all deliveries for a given
address from a single shell script, and then to deliver to just that shell
script in the .qmail file. This requires manually rewinding the
standard input between deliveries; you can do this with
seek0. This is more error-prone, but faster,
since a shell is spawned only once per message. I might write a wrapper for
qmail-local that checks for such a delivery script called
.qmailx adjacent to .qmail, executes it without
forking if it exists, and executes qmail-local without forking
otherwise.
The qtraceaddr Perl script illustrates how qmail
decides how to deliver messages for any addresses given on the command line.
If your qmail installation used non-default values for
conf-qmail, conf-break, or the alias
user, you can specify them in the $QMAIL,
$QMAILBREAK, and $QMAILALIAS environment variables.
For example:
# env QMAILBREAK=+ /path/to/qtraceaddr address@example.org
The mess822-nonroot
patch prevents mess822 from installing its own leapsecs.dat
file in /etc. This is useful for installing mess822 as a
non-root user or when the existing /etc/leapsecs.dat file is
more up-to-date than the one in mess822.